import { IFormulaService, ValueType } from "../interface/IFormulaService";
import { BaseService } from "./BaseService";

import { HyperFormula, CellValue, SimpleCellAddress } from "hyperformula";

export abstract class BaseFormulaService
  extends BaseService
  implements IFormulaService
{
  /**
   * debug only
   */
  hf = HyperFormula.buildEmpty({ licenseKey: "gpl-v3" });
  protected sheetName = "Sheet1";
  protected rowReadyForWrite: { [col: number]: number } =
    this.defaultZeroNumberObject();

  load(): Promise<void> {
    if (!this.hf.doesSheetExist(this.sheetName)) {
      this.hf.addSheet(this.sheetName);
    }
    return Promise.resolve();
  }
  unload(): Promise<void> {
    if (this.hf.doesSheetExist(this.sheetName)) {
      this.hf.removeSheet(this.hf.getSheetId(this.sheetName)!);
    }
    return Promise.resolve();
  }
  /**
   * 在sheet1 row0 col0 处计算公式
   * @param _formula
   */
  calculate(_formula: string): CellValue {
    // if (this.hf.getSheetId(this.sheetName) === undefined) {
    //   throw new Error("Sheet not found.");
    // }
    // if (!this.hf.validateFormula(_formula)) {
    //   throw new Error("Invalid formula.");
    // }
    this.hf.setCellContents(
      { row: 0, col: 0, sheet: this.hf.getSheetId(this.sheetName)! },
      _formula
    );
    return this.hf.getCellValue({
      row: 0,
      col: 0,
      sheet: this.hf.getSheetId(this.sheetName)!,
    });
  }
  listFunctionNames(): string[] {
    return HyperFormula.getRegisteredFunctionNames("enGB");
  }
  getFunctionHelp(_functionName: string): string {
    throw new Error("Method not implemented.");
  }

  setVariable(_value: any, _valueType: ValueType): string | undefined {
    const sheetId = this.hf.getSheetId(this.sheetName)!;
    const addr: SimpleCellAddress = {
      sheet: sheetId,
      col: _valueType,
      row: this.rowReadyForWrite[_valueType],
    };

    this.hf.setCellContents(addr, _value);
    this.rowReadyForWrite[_valueType] += 1;
    return BaseFormulaService.cellAddressToName(addr);
  }
  getVariable(_name: string): CellValue {
    const addr: SimpleCellAddress = BaseFormulaService.nameToCellAddress(_name);
    return this.hf.getCellValue(addr);
  }

  protected static cellAddressToName(add: SimpleCellAddress): string {
    return `sheet:${add.sheet}, col:${add.col}, row:${add.row}`;
  }
  protected static nameToCellAddress(name: string): SimpleCellAddress {
    const [sheet, col, row] = name.split(",");
    return {
      sheet: parseInt(sheet.split(":")[1]),
      col: parseInt(col.split(":")[1]),
      row: parseInt(row.split(":")[1]),
    };
  }

  private defaultZeroNumberObject(): { [key: number]: number } {
    const obj: { [key: number]: number } = {};

    // 重载设置属性的操作符以确保默认值为0
    const handler: ProxyHandler<{ [key: number]: number }> = {
      get(target, prop) {
        if (
          typeof prop === "string" &&
          !isNaN(Number(prop)) &&
          !(prop in target)
        ) {
          // 如果属性不存在，则返回默认值0
          return 0;
        }
        return Reflect.get(target, prop);
      },
      set(target, prop, value) {
        // 设置属性值
        return Reflect.set(target, prop, value);
      },
    };

    // 使用Proxy来创建一个代理对象，该对象会拦截get操作并提供默认值
    return new Proxy(obj, handler);
  }
}
